#include <GL/glut.h>
#include "../draw.h"
#include "screens.h"
#include "externs.h"
#include <cmath>
#include <sstream>

#define OUR_KEY_TAB 9
#define OUR_KEY_SPACE 32

#define CORNER 0
#define FAR 1
#define THIRD 2

#define TURN_TIME 60*25

#define BUFSIZE 1024

#define LEFT 0
#define RIGHT 1

GLuint selectBuf[BUFSIZE];
int buttonMode=LEFT;
int GamePlayScreen::playCount;

int cameraMode=CORNER;

int xmap,ymap,zmap;
int xeye,yeye,zeye;
int xref,yref,zref;
int xviewvector,yviewvector,zviewvector;
int xrightvector,yrightvector,zrightvector;
int xupvector,yupvector,zupvector;

float globalAmbient[]={0.05,0.05,0.05,1};

float lightAmbient[]={0.3,0.3,0.3,1};
float lightDiffuse[]={1,1,1,1};
float lightSpecular[]={0.6,0.6,0.6,1};


float spotlightAmbient[]={0.1,0.1,0.1,1};
float spotlightDiffuse[]={0.8,0.8,0.8,1};
float spotlightSpecular[]={0.5,0.5,0.5,1};


float nightAmbient[]={0,0,0,1};
float nightDiffuse[]={0,0,0,1};
float nightSpecular[]={0,0,0,1};

float lightPosition[4];

float matAmbient[]={0.5,0.5,0.5,1};
float matDiffuse[]={1,1,1,1};
float matSpecular[]={1,1,1,1};
float matEmission[]={0,0,0,1};
float matShininess[]={50};

int keys[512];
int drawMode=BATTLESHIP;

GamePlayScreen::GamePlayScreen()
{
	playCount=0;
}

void GamePlayScreen::setEnvironment(string filePath)
{

	//glEnable(GL_CULL_FACE);

	pickMode=RENDER;
	cursorX=0;
	cursorY=0;

	cout << "Game Play environment will be set" << endl;
	for(int i=0;i<512;i++)
		keys[i]=0;
	game=new Game();
	game->init(filePath);
	xmap=game->getZone().getMap().getMapDimensionX();
	ymap=game->getZone().getMap().getMapDimensionY();
	zmap=game->getZone().getMap().getMapDimensionZ();

	game->setDay();

	xeye=xmap;
	yeye=10;
	zeye=zmap+200;

	xref=xmap/2;
	yref=ymap/2;
	zref=0;

	xviewvector=xref-xeye;
	yviewvector=yref-yeye;
	zviewvector=zref-zeye;

	xrightvector=yeye-yref;
	yrightvector=xref-xeye;
	zrightvector=0;

	xupvector=yviewvector*zrightvector-zviewvector*yrightvector;
	yupvector=zviewvector*xrightvector-xviewvector*zrightvector;
	zupvector=xviewvector*yrightvector-yviewvector*zrightvector;

	lightPosition[0]=xmap*0.9;
	lightPosition[1]=ymap*0.9;
	lightPosition[2]=4*zmap*0.9;
	lightPosition[3]=0;

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,globalAmbient);

	glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);

	glLightfv(GL_LIGHT1, GL_AMBIENT, spotlightAmbient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, spotlightDiffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, spotlightSpecular);
	glLightf(GL_LIGHT1,GL_SPOT_CUTOFF, 45);
	glLightf(GL_LIGHT1,GL_SPOT_EXPONENT, 30);

	glLightfv(GL_LIGHT2, GL_AMBIENT, spotlightAmbient);
	glLightfv(GL_LIGHT2, GL_DIFFUSE, spotlightDiffuse);
	glLightfv(GL_LIGHT2, GL_SPECULAR, spotlightSpecular);
	glLightf(GL_LIGHT2,GL_SPOT_CUTOFF, 45);
	glLightf(GL_LIGHT2,GL_SPOT_EXPONENT, 30);

	glLightfv(GL_LIGHT3, GL_AMBIENT, spotlightAmbient);
	glLightfv(GL_LIGHT3, GL_DIFFUSE, spotlightDiffuse);
	glLightfv(GL_LIGHT3, GL_SPECULAR, spotlightSpecular);
	glLightf(GL_LIGHT3,GL_SPOT_CUTOFF, 30);
	glLightf(GL_LIGHT3,GL_SPOT_EXPONENT, 15);

	glLightfv(GL_LIGHT4, GL_AMBIENT, spotlightAmbient);
	glLightfv(GL_LIGHT4, GL_DIFFUSE, spotlightDiffuse);
	glLightfv(GL_LIGHT4, GL_SPECULAR, spotlightSpecular);
	glLightf(GL_LIGHT4,GL_SPOT_CUTOFF, 30);
	glLightf(GL_LIGHT4,GL_SPOT_EXPONENT, 15);

	glLightfv(GL_LIGHT5, GL_AMBIENT, spotlightAmbient);
	glLightfv(GL_LIGHT5, GL_DIFFUSE, spotlightDiffuse);
	glLightfv(GL_LIGHT5, GL_SPECULAR, spotlightSpecular);
	glLightf(GL_LIGHT5,GL_SPOT_CUTOFF, 45);
	glLightf(GL_LIGHT5,GL_SPOT_EXPONENT, 30);

	glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
	//glShadeModel (GL_SMOOTH);

	/*glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
	glMaterialfv(GL_FRONT, GL_EMISSION, matEmission);
	glMaterialfv(GL_FRONT, GL_AMBIENT, matAmbient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiffuse);
	glMaterialfv(GL_FRONT, GL_SHININESS, matShininess);*/

}


string itos(int i){
	ostringstream buffer;
	buffer << i;
	return buffer.str();
}

void GamePlayScreen::drawTime()
{
	if(TURN_TIME/25-playCount/25>5)
	{
		glColor3f(0.3,0.3,0.3);
		Draw::Text(380,550,itos(TURN_TIME/25-playCount/25),-1,BIG);
	}
	else
	{
		glColor3f(1,0.2,0.2);
		Draw::Text(380,550,itos(TURN_TIME/25-playCount/25),-1,BIGGER);
	}
}

void GamePlayScreen::processHits(GLint hits, GLuint buffer[])
{
	unsigned int i, j;
	GLuint names, *ptr, minZ,*ptrNames, numberOfNames;

	//printf ("hits = %d\n", hits);
	ptr = (GLuint *) buffer;
	minZ = 0xffffffff;
	for (i = 0; (int)i < hits; i++) {
	  names = *ptr;
	  ptr++;
	  if (*ptr < minZ) {
		  numberOfNames = names;
		  minZ = *ptr;
		  ptrNames = ptr+2;
	  }

	  ptr += names+2;
	}
	//printf ("The closest hit names are ");
	ptr = ptrNames;
	int selectedPlayer=-1;
	int selectedShip=-1;
	for (j = 0; j < numberOfNames; j++,ptr++) {
	// printf ("%d ", *ptr);
	 if(j==0)
		 selectedPlayer=*ptr;
	 else if(j==1)
		 selectedShip=*ptr;
	}
	//printf ("\n");

	if(selectedPlayer!=-1 && selectedShip!=-1 && selectedPlayer==playerId)
		game->setCurrentShip(selectedShip);
}


void GamePlayScreen::stopPicking() {

	GLint hits;
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glFlush();
	hits=glRenderMode(GL_RENDER);
	if (hits!=0){
		processHits(hits,selectBuf);
	}
	pickMode = RENDER;
}


void GamePlayScreen::startPicking() {
	GLint viewport[4];
	float ratio;

	glSelectBuffer(BUFSIZE,selectBuf);

	glGetIntegerv(GL_VIEWPORT,viewport);

	glRenderMode(GL_SELECT);

	glInitNames();

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();

	gluPickMatrix(cursorX,viewport[3]-cursorY,5,5,viewport);
	ratio = (viewport[2]+0.0) / viewport[3];
	gluPerspective(45,ratio,0.1,10*game->getZone().getMap().getMapDimensionY());
	glMatrixMode(GL_MODELVIEW);
}



void GamePlayScreen::display(void)
{
	int isPicking=0;
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_CULL_FACE);
	glEnable(GL_NORMALIZE);

	//Port Lights
	if(game->isDay==NIGHT)
	{
		glEnable(GL_LIGHT1);
		glEnable(GL_LIGHT2);
		glEnable(GL_LIGHT5);
	}

	glClearDepth(1);
	glClearColor(0,0,0,0);
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45,800.0/600.0,1,10*game->getZone().getMap().getMapDimensionY());

	if(pickMode==PICKING)
	{
		isPicking=1;
		startPicking();
	}

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	if(cameraMode==CORNER || cameraMode==FAR)
		gluLookAt (xeye,yeye,zeye,xref,yref,zref,xupvector,yupvector,zupvector);
	if(cameraMode==THIRD)
	{
		glRotatef(-75,1,0,0);
		glTranslatef(0,400,0);

		glRotatef(-game->getCurrentShipsOrientation(),0,0,1);
		glTranslatef(-game->getCurrentShipsPosition().first,-game->getCurrentShipsPosition().second,-game->getZone().getMap().getSeaLevel()*game->getZone().getMap().getMapDimensionZ()/255.0-200);
	}
	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);



	game->draw(drawMode,isPicking);




	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHT1);
	glDisable(GL_LIGHT2);
	glDisable(GL_LIGHT5);
	glDisable(GL_LIGHTING);


	//Draw Boxes
	/*glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);					// Turn Blending On
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);	// Set The Blending Function For Translucency

	glColor4f(0.5,0.5,0.5,0.95);
	glBegin(GL_QUADS);
	{
		glVertex3f(0,0,-100);
		glVertex3f(100,0,-100);
		glVertex3f(100,600,-100);
		glVertex3f(0,600,-100);

		glVertex3f(700,0,-100);
		glVertex3f(800,0,-100);
		glVertex3f(800,600,-100);
		glVertex3f(700,600,-100);
	}
	glEnd();

	glDisable(GL_BLEND);

	glEnable(GL_DEPTH_TEST);
	game->drawInfo();*/


	glDisable(GL_CULL_FACE);
	glDisable(GL_COLOR_MATERIAL);
	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_NORMALIZE);


	glDisable(GL_LIGHT1);
	glDisable(GL_LIGHT2);



	/*glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,800,0,600,-300,300);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	drawTime();*/

	if(pickMode==PICKING)
		stopPicking();
	else
		glutSwapBuffers();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,800,0,600,-300,300);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void GamePlayScreen::calculator()
{
	game->moveCurrentShip();
}

void GamePlayScreen::handler()
{
	//Usage of BattleShip
	if(keys[GLUT_KEY_DOWN]==1)
	{
		game->moveCurrentShip(GLUT_KEY_DOWN);
	}
	if(keys[GLUT_KEY_UP]==1)
	{
		game->moveCurrentShip(GLUT_KEY_UP);
	}
	if(keys[GLUT_KEY_RIGHT]==1)
	{
		game->moveCurrentShip(GLUT_KEY_RIGHT);
	}
	if(keys[GLUT_KEY_LEFT]==1)
	{
		game->moveCurrentShip(GLUT_KEY_LEFT);
	}

}

void GamePlayScreen::endGame()
{
	for(int i=0;i<512;i++)
		keys[i]=0;
	delete game;
	screenMode=END;
	glutPostRedisplay();
}

void GamePlayScreen::endTurn(int p)
{
	GamePlayScreen *pThis= (GamePlayScreen*)p;
	for(int i=0;i<512;i++)
		keys[i]=0;
	pThis->game->resetStates();

	if(pThis->game->isStatic())
	{
		cout << "Now we're static" << endl;
		playCount=0;
		screenMode=TURN;
		glutPostRedisplay();
	}
	else
	{
		pThis->calculator();
		glutTimerFunc(40,endTurn,p);
		glutPostRedisplay();
	}
}

void GamePlayScreen::timer(int p)
{
	GamePlayScreen *pThis= (GamePlayScreen*)p;

	if(playCount==-1)
	{
		pThis->endGame();
		return;
	}
	if(++playCount>TURN_TIME)
	{
		pThis->endTurn(p);
		return;
	}
	else
	{
		pThis->handler();
		pThis->calculator();
		glutPostRedisplay();
		glutTimerFunc(40,timer,p);
	}
}

void GamePlayScreen::start()
{
	playCount=0;
	glutTimerFunc(40,timer,(int)this);
}


void GamePlayScreen::keyboard(unsigned char key,int x, int y)
{

	//Selection Of Weapons
	if(playCount<TURN_TIME)
	{
		keys[key]=1;
		//SILLY GAME GRAPHICS
		if(keys['1']==1)
			drawMode=BATTLESHIP;
		if(keys['2']==1)
			drawMode=TRADESHIP;
		if(keys['3']==1)
			drawMode=MISSILE;
		if(keys['4']==1)
			drawMode=MINE;

		if(keys['5'])
		{
			game->setDay();
			glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
			glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
			glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
		}
		if(keys['6'])
		{
			game->setNight();
			glLightfv(GL_LIGHT0, GL_AMBIENT, nightAmbient);
			glLightfv(GL_LIGHT0, GL_DIFFUSE, nightDiffuse);
			glLightfv(GL_LIGHT0, GL_SPECULAR, nightSpecular);
		}


		//SILLY CAMERA MODES
		if(keys['8']==1)
		{
			cameraMode=CORNER;
			xeye=xmap;
			yeye=0;
			zeye=zmap+500;

			xref=xmap/2;
			yref=ymap/2;
			zref=0;

			xviewvector=xref-xeye;
			yviewvector=yref-yeye;
			zviewvector=zref-zeye;

			xrightvector=yeye-yref;
			yrightvector=xref-xeye;
			zrightvector=0;

			xupvector=yviewvector*zrightvector-zviewvector*yrightvector;
			yupvector=zviewvector*xrightvector-xviewvector*zrightvector;
			zupvector=xviewvector*yrightvector-yviewvector*zrightvector;
		}
		if(keys['9']==1)
		{
			cameraMode=FAR;
			xeye=xmap/2;
			yeye=ymap/2;
			zeye=zmap+500;

			xref=xmap/2;
			yref=ymap/2;
			zref=0;

			xupvector=0;
			yupvector=1;
			zupvector=0;
		}
		if(keys['0']==1)
			cameraMode=THIRD;

		if(cameraMode==FAR)
		{
			if(keys['z']==1 || keys['Z']==1)
			{
				zeye+=15;
			}
			if(keys['x']==1 || keys['X']==1)
			{
				zeye-=15;
			}
		}

		//Selection Of BattleShips
		if(keys[OUR_KEY_TAB]==1)
		{
			cout << "Tab will be executed" << endl;
			game->selectNextShip();
		}

		//Usage of TradeShips
		if(keys['t']==1 || keys['T']==1)
		{
			;
		}
		if(keys['y']==1 || keys['Y']==1)
		{
			;
		}
		if(keys['u']==1 || keys['U']==1)
		{
			;
		}


		//Usage of Weapons
		if(keys[OUR_KEY_SPACE]==1)
		{
			;
		}
	}



	if(key==13)
	{
		cout << "enter'a bastin" << endl;
		for(int i=0;i<512;i++)
			keys[i]=0;
		playCount=TURN_TIME;
	}
	else if(key==27)
	{
		cout << "esc'ye bastin" << endl;
		playCount=-1;
	}

}

void GamePlayScreen::special(int key,int x, int y)
{
	keys[key]=1;
}

void GamePlayScreen::specialUp(int key,int x, int y)
{
	keys[key]=0;
}

void GamePlayScreen::keyboardUp(unsigned char key,int x, int y)
{
	keys[key]=0;
}


void GamePlayScreen::mouse(int button, int state,int x, int y)
{
	if(button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
		buttonMode=RIGHT;
	if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
	{
		cursorX=x;
		cursorY=y;
		pickMode=PICKING;
		buttonMode=LEFT;
		glutPostRedisplay();
	}
}

void GamePlayScreen::motion(int x, int y)
{
	if(cameraMode==CORNER && buttonMode==RIGHT)
	{
		xeye=float(x)/800.0*xmap;
		yeye=10;
		zeye=float(y)/600.0*ymap;

		xref=xmap/2;
		yref=ymap/2;
		zref=0;

		xviewvector=xref-xeye;
		yviewvector=yref-yeye;
		zviewvector=zref-zeye;

		xrightvector=yeye-yref;
		yrightvector=xref-xeye;
		zrightvector=0;

		xupvector=yviewvector*zrightvector-zviewvector*yrightvector;
		yupvector=zviewvector*xrightvector-xviewvector*zrightvector;
		zupvector=xviewvector*yrightvector-yviewvector*zrightvector;

		//glutPostRedisplay();
	}

}

void GamePlayScreen::passiveMotion(int x, int y)
{

}
